﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NHibernate.Collection.Generic;
using NHibernate;
using System.Net.Mail;
using Mailer.Utilities;
using System.Globalization;
using Mailer.Utilities.MailPoller;

namespace Mailer.Model.Types
{
	public class Mail
	{
		public virtual Guid ID { get; set; }
		public virtual Guid ApplicationID { get; set; }

		public virtual DateTime CreatedDate { get; set; }
		public virtual DateTime UpdatedDate { get; set; }

		public virtual Guid CreatedBy { get; set; }
		public virtual Guid UpdatedBy { get; set; }

		public virtual string Name { get; set; }

		public virtual int State { get; set; }


		public virtual IList<MailProperty> Properties { get; set; }
		public virtual IList<List> Lists { get; set; }

		public Mail()
		{
			Properties = new List<MailProperty>();
			Lists = new List<List>();
		}

		public virtual string GetPropertyValue(string propertyname)
		{
			return GetPropertyValue(propertyname, "");
		}

		public virtual string GetPropertyValue(string propertyname, string defaultvalue)
		{
			foreach (MailProperty ap in Properties)
			{
				if (ap.Name == propertyname)
					return ap.Value;
			}

			return defaultvalue;
		}

		public virtual void SetPropertyValue(ISession session, string propertyname, string propertyvalue)
		{
			//	ISession sess = SessionUtilities.GetSession();
			//	if (sess != null)
			//	{
			bool found = false;
			foreach (MailProperty ap in Properties)
			{
				if (ap.Name == propertyname)
				{
					ap.Value = propertyvalue;
					session.Save(ap);
					found = true;
				}
			}

			if (!found)
			{
				MailProperty newap = new MailProperty();
				newap.MailID = ID;
				newap.Name = propertyname;
				newap.Value = propertyvalue;
				session.Save(newap);
				Properties.Add(newap);
			}

			//	}
		}

		public virtual MailAddress GetSenderAddress()
		{
			return new MailAddress(GetPropertyValue("senderemail"), GetPropertyValue("sendername"));
		}

		public virtual MailAddress GetSenderAddress(string overrideemail)
		{
			return new MailAddress(overrideemail, GetPropertyValue("sendername"));
		}

		public virtual MailAddress GetToAddress()
		{
			return new MailAddress(GetPropertyValue("recipientemail"), GetPropertyValue("recipientname"));
		}

		public virtual MailAddress GetReplyToAddress()
		{
			return new MailAddress(GetPropertyValue("replytoemail"));
		}

		public virtual string PrepareBody(string templatedata, Recipient recip)
		{
			Dictionary<string, string> translation = new Dictionary<string, string>();

			if (recip != null)
			{
				translation.Add("mail.unsubscribe.link", Configuration.RootURL + "public/m/" + ID + "/" + recip.ID + "/unsubscribe");
				translation.Add("mail.subscribe.link", Configuration.RootURL + "public/m/" + ID + "/" + recip.ID + "/subscribe");
				translation.Add("mail.tracker.link", Configuration.RootURL + "public/m/" + ID + "/" + recip.ID + "/shim.gif");
			}
			else
			{
				translation.Add("mail.unsubscribe.link", Configuration.RootURL + "public/m/" + ID + "/unsubscribe");
				translation.Add("mail.subscribe.link", Configuration.RootURL + "public/m/" + ID + "/subscribe");
				translation.Add("mail.tracker.link", Configuration.RootURL + "public/m/" + ID + "/shim.gif");
			}

			translation.Add("mail.link", Configuration.RootURL + "public/m/" + ID + "/html");

			translation.Add("app.subscribe.link", Configuration.RootURL + "public/a/" + ApplicationID + "/subscribe");
			translation.Add("app.unsubscribe.link", Configuration.RootURL + "public/a/" + ApplicationID + "/unsubscribe");

			Dictionary<string, string>.Enumerator e = translation.GetEnumerator();
			while (e.MoveNext())
			{
				templatedata = templatedata.Replace("{" + e.Current.Key + "}", e.Current.Value);
			}

			return templatedata;
		}

		private MailMessage PrepareBaseMail(Recipient recipient)
		{
			string htmltemplate = GetPropertyValue("htmlbody").Trim();
			string texttemplate = GetPropertyValue("plaintextbody").Trim();

			string htmlbody = PrepareBody(htmltemplate, recipient);
			string textbody = PrepareBody(texttemplate, recipient);

			MailMessage mm = new MailMessage();
			Application app = null;

			ISession sess = SessionUtilities.BeginSession();
			if (sess != null)
			{
				app = sess.Get<Application>(ApplicationID);
				SessionUtilities.EndSession(sess);
			}

			// mm.Headers.Add("X-Sender", GetSenderAddress().ToString());
			mm.ReplyTo = GetReplyToAddress();

			mm.Subject = GetPropertyValue("subject");

			if (!string.IsNullOrEmpty(htmltemplate) && !string.IsNullOrEmpty(texttemplate))
			{
			//	log4net.LogManager.GetLogger(typeof(Mail)).Debug("Preparing multipart message:\n\n" + htmlbody + "\n\n" + textbody);
				mm.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(textbody, null, "text/plain"));
				mm.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(htmlbody, null, "text/html"));
			}
			else if (!string.IsNullOrEmpty(htmltemplate))
			{
			//	log4net.LogManager.GetLogger(typeof(Mail)).Debug("Preparing html message:\n\n" + htmlbody);
				mm.Body = htmlbody;
				mm.IsBodyHtml = true;
			}
			else if (!string.IsNullOrEmpty(texttemplate))
			{
			//	log4net.LogManager.GetLogger(typeof(Mail)).Debug("Preparing plaintext message:\n\n" + textbody);
				mm.Body = textbody;
				mm.IsBodyHtml = false;
			}

			string trackid = "";
			if( recipient != null ) 
				trackid = MailID.Generate(ID, recipient.ID);
			else
				trackid = MailID.Generate(ID);

			mm.Headers.Add("X-Mailer", Configuration.VersionString);

			mm.Headers.Add("X-NMailer-ID", trackid);
			// mm.Headers.Add("Envelope-ID", trackid);

			string trackingmode = app.GetPropertyValue("trackingmode", "");
			if (trackingmode == "smtpserver")
			{
				string publicaddress = app.GetPropertyValue("trackingmailpublicaddress", "");
				string trackaddress = trackid + "@" + Configuration.BounceSmtpServerAddress;

			//	mm.Headers.Add("Disposition-Notification-To", "<" + trackaddress + ">");
				// mm.Headers.Add("Notice-Requested-Upon-Delivery-To", trackaddress);
				// mm.Headers.Add("Return-Receipt-To", "<" + trackaddress + ">");
				// mm.Headers.Add("Read-Receipt-To", "<" + trackaddress + ">");
				// mm.Headers.Add("Return-Path", trackaddress);
				mm.From = GetSenderAddress(trackaddress);
			}
			else if (trackingmode == "mailbox")
			{
				string publicaddress = app.GetPropertyValue("trackingmailpublicaddress", "");

			//	mm.Headers.Add("Disposition-Notification-To", "<" + publicaddress + ">");
				// mm.Headers.Add("Notice-Requested-Upon-Delivery-To", publicaddress);
				// mm.Headers.Add("Return-Receipt-To", "<" + publicaddress + ">");
				// mm.Headers.Add("Read-Receipt-To", "<" + publicaddress + ">");
				// mm.Headers.Add("Return-Path", publicaddress);
				mm.From = GetSenderAddress(publicaddress);
			}
			else
			{
				mm.From = GetSenderAddress();
			}

		//	mm.de
		//	mm.DeliveryNotificationOptions = DeliveryNotificationOptions.OnSuccess | DeliveryNotificationOptions.OnFailure | DeliveryNotificationOptions.Delay;

			return mm;
		}

		public virtual MailMessage PrepareMail(Recipient recip)
		{
			if (recip != null)
			{
				MailMessage mm = PrepareBaseMail(recip);
				mm.To.Add(recip.GetAddress());
				return mm;
			}
			MailMessage mm2 = PrepareBaseMail(null);
			return mm2;			
		}

		public virtual MailMessage PrepareMail(Recipient[] recips)
		{
			MailMessage mm = PrepareBaseMail(null);
			mm.To.Add(GetToAddress());
			if (recips != null)
			{
				foreach (Recipient r in recips)
					mm.Bcc.Add(r.GetAddress());
			}
			return mm;
		}

		public virtual int NumTotal
		{
			get
			{
				int ret = 0;
				ISession sess = SessionUtilities.BeginSession();
				if (sess != null)
				{
					ret = (int)(long)sess.CreateQuery("select count(sq) as n from SendQueue as sq where sq.MailID = :mail")
						.SetParameter("mail", ID)
						.UniqueResult();

					SessionUtilities.EndSession(sess);
				}
				return ret;
			}
		}

		public virtual int NumSentTotal
		{
			get
			{
				int ret = 0;
				ISession sess = SessionUtilities.BeginSession();
				if (sess != null)
				{
					ret = (int)(long)sess.CreateQuery("select count(sq) as n from SendQueue as sq where sq.MailID = :mail and (sq.State = :state1 or sq.State = :state2)")
						.SetParameter("mail", ID)
						.SetParameter("state1", (int)QueueState.Sent)
						.SetParameter("state2", (int)QueueState.Failed)
						.UniqueResult();

					SessionUtilities.EndSession(sess);
				}
				return ret;
			}
		}

		public virtual int PercentDone
		{
			get
			{
				if (NumTotal < 1)
					return 100;

				return (int)((NumSentTotal * 100) / NumTotal);
			}
		}

		public virtual int NumLeftQueued
		{
			get
			{
				int ret = 0;
				ISession sess = SessionUtilities.BeginSession();
				if (sess != null)
				{
					ret = (int)(long)sess.CreateQuery("select count(sq) as n from SendQueue as sq where sq.MailID = :mail and sq.State = :state1")
						.SetParameter("mail", ID)
						.SetParameter("state1", (int)QueueState.NotSent)
						.UniqueResult();

					SessionUtilities.EndSession(sess);
				}
				return ret;
			}
		}

		public virtual int NumSendAndFailed
		{
			get
			{
				int ret = 0;
				ISession sess = SessionUtilities.BeginSession();
				if (sess != null)
				{
					ret = (int)(long)sess.CreateQuery("select count(sq) as n from SendQueue as sq where sq.MailID = :mail and sq.State = :state1")
						.SetParameter("mail", ID)
						.SetParameter("state1", (int)QueueState.Failed)
						.UniqueResult();

					SessionUtilities.EndSession(sess);
				}
				return ret;
			}
		}

		public virtual int NumSentSuccessfully
		{
			get
			{
				int ret = 0;
				ISession sess = SessionUtilities.BeginSession();
				if (sess != null)
				{
					ret = (int)(long)sess.CreateQuery("select count(sq) as n from SendQueue as sq where sq.MailID = :mail and sq.State != :state1")
						.SetParameter("mail", ID)
						.SetParameter("state1", (int)QueueState.NotSent)
						.UniqueResult();
					SessionUtilities.EndSession(sess);
				}
				return ret;
			}
		}

		public virtual int NumSentButNotRead
		{
			get
			{
				int ret = 0;
				ISession sess = SessionUtilities.BeginSession();
				if (sess != null)
				{
					ret = (int)(long)sess.CreateQuery("select count(sq) as n from SendQueue as sq where sq.MailID = :mail and sq.State = :state1")
						.SetParameter("mail", ID)
						.SetParameter("state1", (int)QueueState.Sent)
						.UniqueResult();
					SessionUtilities.EndSession(sess);
				}
				return ret;
			}
		}


		public virtual int NumRead
		{
			get
			{
				int ret = 0;
				ISession sess = SessionUtilities.BeginSession();
				if (sess != null)
				{
					ret = (int)(long)sess.CreateQuery("select count(sq) as n from SendQueue as sq where sq.MailID = :mail and sq.State = :state1")
						.SetParameter("mail", ID)
						.SetParameter("state1", (int)QueueState.Read)
						.UniqueResult();
					SessionUtilities.EndSession(sess);
				}
				return ret;
			}
		}
	}
}
